/** @file    MediaZone.cpp
 *  @author  Alessandro Polo
 *  @version $Id: MediaZone.cpp 2829 2010-08-02 20:45:47Z alex $
 *  @brief
 * File containing methods for the wosh::entertainment::MediaZone class.
 * The header for this class can be found in MediaZone.h, check that file
 * for class description.
 ****************************************************************************/
/* Copyright (c) 2007-2010, WOSH - Wide Open Smart Home 
 * by Alessandro Polo - OpenSmartHome.com
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *     * Neither the name of the OpenSmartHome.com WOSH nor the
 *       names of its contributors may be used to endorse or promote products
 *       derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY Alessandro Polo ''AS IS'' AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL Alessandro Polo BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 ****************************************************************************/
 
 #include <framework/entertainment/MediaZone.h>
 #include <core/ObjectAllocator.h>
 #include <core/List.h>
 #include <core/Table.h>
 #include <core/DataModels.h>


using namespace std;
namespace wosh {
 namespace entertainment {

 WOSH_REGISTER(wosh::entertainment::MediaZone, "wosh::Object", 1.0, _static_MediaZone )

//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////// CONSTRUCTORS

MediaZone::MediaZone()
	: Object() {
	clear();
 }

MediaZone::MediaZone( const MediaZone& m )
	: Object(m) {
	*this = m;
 }

//////////////////////////////////////////////////////////////////////////////////////////////// CONSTRUCTORS
//////////////////////////////////////////////////////////////////////////////////////////////////////////////

void MediaZone::clear() {
	this->id = 0;
	this->timestamp = 0;
	setZoneType( MediaZone::TYPE_UNKNOWN );
	setZoneRole( MediaZone::ROLE_UNKNOWN );
	setRanking ( 0 );

	setName("");
	setParent("");

	this->children.clear();

	this->playerUri.clear();
	this->locationUri = "";

	setVolume(0);
	setMuted(false);

	Properties.transactionBeginWrite();
	Properties.update(_MediaZone_KEY_VolumeDefault, 30 );
	Properties.update(_MediaZone_KEY_VolumeMin, 0 );
	Properties.update(_MediaZone_KEY_VolumeMax, 100 );
	Properties.transactionEnd();

	this->keyMappings.clear();

	this->playlist.clear();
	this->Properties.clear();
 }

//////////////////////////////////////////////////////////////////////////////////////////////////////////////

void MediaZone::setName( const std::string& value ) {
	Object::setName( value );
	Properties.set(_KEY_name, value );
 }

void MediaZone::setParent( const string& value ) {
	this->parent = value;
	Properties.set(_KEY_parent, value );
 }

void MediaZone::setZoneType( MediaZone::ZONE_TYPE type ) {
	this->zoneType = type;
	Properties.set(_MediaZone_KEY_ZoneType, (int)type );
 }
void MediaZone::setZoneRole( MediaZone::ZONE_ROLE role ) {
	this->zoneRole = role;
	Properties.set(_MediaZone_KEY_ZoneRole, (int)role );
 }

void MediaZone::setRanking( double value ) {
	this->ranking = value;
	Properties.set(_MediaZone_KEY_ZoneRanking, value );
 }

void MediaZone::setVolume( int value ) { 
	this->volumeCurrent = value;
	Properties.set(_MediaZone_KEY_VolumeCurrent, value );
 }

void MediaZone::setMuted( bool value ) { 
	this->volumeMuted = value;
	Properties.set(_MediaZone_KEY_VolumeMuted, value );
 }

//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////

MediaZone& MediaZone::operator=(const MediaZone& m) {
	if (this == &m) return *this; // Same object?
	(Object&)*this = (const Object&)m;

	this->id = m.id;
	this->timestamp = m.timestamp;
	this->zoneType = m.zoneType;
	this->zoneRole = m.zoneRole;
	this->ranking = m.ranking;

	this->parent = m.parent;
	this->children.clear();

	this->playerUri = m.playerUri;
	this->locationUri = m.locationUri;

	this->keyMappings.getMap().clear();

	this->playlist = m.playlist;
	this->Properties = m.Properties;

	return *this;
 }

bool MediaZone::operator==(const MediaZone &other) const {
	if ( (Object&)*this != (const Object&)other ) return false;
	if ( this->zoneType != other.zoneType ) return false;
	if ( this->zoneRole != other.zoneRole ) return false;
	if ( this->parent != other.parent ) return false;
	return true;
 }

//////////////////////////////////////////////////////////////////////////////////////////////////////////////

bool MediaZone::updateHash( DataHashContext* hash_context ) const {
	if ( hash_context == NULL ) return false;
	bool ret = true;
	ret = hash_context->update( this->id ) & ret;
	ret = hash_context->update( this->timestamp ) & ret;
	ret = hash_context->update( this->zoneType ) & ret;
	ret = hash_context->update( this->zoneRole ) & ret;
	ret = hash_context->update( this->ranking ) & ret;
	ret = hash_context->update( this->parent ) & ret;
	ret = hash_context->update( this->children ) & ret;
	ret = hash_context->update( this->locationUri ) & ret;
	ret = this->playerUri.updateHash( hash_context ) & ret;
	ret = this->playerIProv.updateHash(hash_context) & ret;
	ret = hash_context->update( this->volumeMuted ) & ret;
	ret = hash_context->update( this->volumeCurrent ) & ret;
	ret = this->playlist.updateHash(hash_context) & ret;
	ret = this->Properties.updateHash(hash_context) & ret;
	return ret;
 }

//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////

DataFieldCollector<MediaZone>* MediaZone::getDataFields() {
	DataFieldCollector<MediaZone>* fields = new DataFieldCollector<MediaZone>();
	fields->add<const std::string&, Variant>(&MediaZone::getName, "Name", 0);
	fields->add<const std::string&, Variant>(&MediaZone::getLocationURI, "Location", 1);
	fields->add<const URI&,URI>(&MediaZone::getPlayerURI, "PlayerDevice", 2);
	fields->add<const std::string&, Variant>(&MediaZone::getParent, "Parent", 3);
	fields->add<MediaZone::ZONE_ROLE, Variant>(&MediaZone::getZoneRole, "ZoneRole", 4);
	fields->add<MediaZone::ZONE_TYPE, Variant>(&MediaZone::getZoneType, "ZoneType", 5);
	fields->add<long, Variant_DT>(&MediaZone::getSeen, "Seen", 6);
	fields->add<const std::string&,Variant>(&MediaZone::getEntityID, "EntityID", 7, false);
	fields->add<const Permission&,Permission>(&MediaZone::getPermission, "Permission", 8, false);
	fields->add<const char*,Variant>(&MediaZone::getClassName, "Type", 9);
	return fields;
 }
 
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////

Table* MediaZone::getKeyMappingsAsTable() const {
	this->keyMappings.transactionBeginRead();
	Table* tbl = new Table(this->keyMappings.size(), 2, true);
	tbl->setTableName("Mappings of " + this->getName() );
	tbl->setHeaderHorizontal("URI", 0);
	tbl->setHeaderHorizontal("Actions", 1);
	unsigned int iRow = 0;
	MapT<URI, int>::ConstIterator it;
	const MapT<URI, int>::ConstIterator it_end = this->keyMappings.end();
	for ( it=this->keyMappings.begin(); it!=it_end; ++it, ++iRow ) {
		tbl->set( it->first.clone(), iRow, 0);
		tbl->set<Variant>( it->second, iRow, 1);
	 }
	this->keyMappings.transactionEnd();
	return tbl;
 }

//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////

string MediaZone::getCommandAsString( int value ) {
	if ( value == (int)MediaZone::COMMAND_PLAY )		return "PLAY";
	else if ( value == (int)MediaZone::COMMAND_TRACK )	return "TRACK";
	else if ( value == (int)MediaZone::COMMAND_VOLUME )	return "VOLUME";
	return "UNKNOWN";
 }

int MediaZone::getCommandFromString( const string& value ) {
	if ( value == "PLAY" )			return (int)MediaZone::COMMAND_PLAY;
	else if ( value == "TRACK" )	return (int)MediaZone::COMMAND_TRACK;
	else if ( value == "VOLUME" )	return (int)MediaZone::COMMAND_VOLUME;
	return (int)MediaZone::COMMAND_UNKNOWN;
 }

//////////////////////////////////////////////////////////////////////////////////////////////////////////////

MediaZone::ZONE_TYPE MediaZone::getZoneTypeFromString( const string& value ) {
	if ( value == "STATIC" )		return MediaZone::TYPE_STATIC;
	else if ( value == "DYNAMIC" )	return MediaZone::TYPE_DYNAMIC;
	else if ( value == "MIXED" )	return MediaZone::TYPE_MIXED;
	return MediaZone::TYPE_UNKNOWN;
 }

string MediaZone::getZoneTypeAsString( MediaZone::ZONE_TYPE value ) {
	if ( value == MediaZone::TYPE_STATIC )			return "STATIC";
	else if ( value == MediaZone::TYPE_DYNAMIC )	return "DYNAMIC";
	else if ( value == MediaZone::TYPE_MIXED )		return "MIXED";
	return "UNKNOWN";
 }

//////////////////////////////////////////////////////////////////////////////////////////////////////////////

MediaZone::ZONE_ROLE MediaZone::getZoneRoleFromString( const std::string& value ) {
	if ( value == "MASTER" )		return MediaZone::ROLE_MASTER;
	else if ( value == "SLAVE" )	return MediaZone::ROLE_SLAVE;
	else if ( value == "FORK" )		return MediaZone::ROLE_FORK;
	return MediaZone::ROLE_UNKNOWN;
 }

std::string MediaZone::getZoneRoleAsString( MediaZone::ZONE_ROLE value ) {
	if ( value == MediaZone::ROLE_MASTER )		return "MASTER";
	else if ( value == MediaZone::ROLE_SLAVE )	return "SLAVE";
	else if ( value == MediaZone::ROLE_FORK )	return "FORK";
	return "UNKNOWN";
 }

//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////

 }; // namespace entertainment
}; // namespace wosh
